///////////////////////////////////////////////////////////////////////
// DiscFormatRawCD.cpp
//
// Wrapper for IDiscFormat2RawCD Interface
//
// Written by Nic Wilson
//

#include "StdAfx.h"
#include "DiscRecorder.h"
#include "DiscFormatRawCD.h"
#include "DiscFormatRawCDEvent.h"

CDiscFormatRawCD::CDiscFormatRawCD(void)
: m_discFormatRawCD(NULL)
, m_mediaTypesArray(NULL)
, m_hResult(0)
, m_hNotificationWnd(NULL)
, m_closeMedia(true)
{
}

CDiscFormatRawCD::~CDiscFormatRawCD(void)
{
	if (m_discFormatRawCD != NULL)
	{
		m_discFormatRawCD->Release();
		m_discFormatRawCD = NULL;  
	}
}

///////////////////////////////////////////////////////////////////////
//
// CDiscFormatRawCD::Initialize()
//
// Description:
//		Creates and initializes the IDiscFormat2Data interface
//
bool CDiscFormatRawCD::Initialize(CDiscRecorder* pDiscRecorder, const CString& clientName)
{
	ASSERT(pDiscRecorder != NULL);
	if (pDiscRecorder == NULL)
	{
		m_errorMessage = _T("Error - CDiscFormatData::Initialize - pDiscRecorder is NULL");
		return false;
	}
	// Initialize the IDiscFormat2RawCD Interface
	m_hResult = CoCreateInstance(__uuidof(MsftDiscFormat2RawCD), NULL, CLSCTX_INPROC_SERVER,
			__uuidof(IDiscFormat2RawCD), (void**)&m_discFormatRawCD);
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("Unable to Initialize IDiscFormat2RawCD - Error:0x%08x"), m_hResult);
		return false;
	}
	// Setup the Disc Format Information
	VARIANT_BOOL isSupported = VARIANT_FALSE;
	m_hResult = m_discFormatRawCD->IsRecorderSupported(pDiscRecorder->GetInterface(), &isSupported);
	if (isSupported == VARIANT_FALSE)
	{
		m_errorMessage = _T("Recorder not supported");
		return false;
	}
	m_hResult = m_discFormatRawCD->put_Recorder(pDiscRecorder->GetInterface());
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2RawCD->put_Recorder Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	m_hResult = m_discFormatRawCD->put_ClientName(clientName.AllocSysString());
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2RawCD->put_ClientName Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	m_hResult = m_discFormatRawCD->get_SupportedMediaTypes(&m_mediaTypesArray);
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2RawCD->get_SupportedMediaTypes Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	VARIANT_BOOL b;
	m_hResult = m_discFormatRawCD->IsCurrentMediaSupported(pDiscRecorder->GetInterface(), &b);
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2RawCD->IsCurrentMediaSupported Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	// NOW PREPARE THE MEDIA, it will be ready to use
	m_hResult = m_discFormatRawCD->PrepareMedia();
	if (!SUCCEEDED(m_hResult))
	{
		m_errorMessage.Format(_T("IDiscFormat2RawCD->PrepareMedia Failed - Error:0x%08x"), m_hResult);
		return false;
	}
	return true;
}

void CDiscFormatRawCD::FreeRecorder()
{
	if ((m_discFormatRawCD) != NULL) 
	{
		// Release the media now that we are done
		m_discFormatRawCD->ReleaseMedia();
		m_discFormatRawCD->put_Recorder(NULL);
	}
}

ULONG CDiscFormatRawCD::GetTotalSupportedMediaTypes()
{
	if (m_mediaTypesArray == NULL)
		return 0;

	return m_mediaTypesArray->rgsabound[0].cElements;
}

int CDiscFormatRawCD::GetSupportedMediaType(ULONG index)
{
	ASSERT(index < GetTotalSupportedMediaTypes());
	if (index < GetTotalSupportedMediaTypes())
	{
		if (m_mediaTypesArray)
		{
			return ((VARIANT*)(m_mediaTypesArray->pvData))[index].intVal;
		}
	}

	return 0;
}

bool CDiscFormatRawCD::Burn(HWND hNotificationWnd, IStream* streamData)
{
	if (m_discFormatRawCD == NULL)
		return false;

	if (hNotificationWnd == NULL)
		return false;

	if (streamData == NULL)
		return false;

	m_streamData = streamData;
	m_hNotificationWnd = hNotificationWnd;

	// Create the event sink
	CDiscFormatRawCDEvent* eventSink = CDiscFormatRawCDEvent::CreateEventSink();
	if (eventSink == NULL)
	{
		m_errorMessage = _T("Unable to create event sink");
		return false;
	}

	if (!eventSink->ConnectDiscFormatRawCD(this))
	{
		m_errorMessage = _T("Unable to connect event sink with interface");
		return false;
	}

	eventSink->SetHwnd(m_hNotificationWnd);
	// set up options on disc format
	// NOTE: this will change later to put a different mode when it's fully implemented
	if (SUCCEEDED(m_hResult))
	{
		m_hResult = m_discFormatRawCD->put_RequestedSectorType(IMAPI_FORMAT2_RAW_CD_SUBCODE_IS_RAW); //IMAPI_FORMAT2_RAW_CD_SUBCODE_PQ_ONLY);
		if (FAILED(m_hResult))
		{
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("FAILED iDiscFormatRaw->put_RequestedSectorType"));
		}
	}
	// burn stream
	if (SUCCEEDED(m_hResult))
	{
		m_hResult = m_discFormatRawCD->WriteMedia(streamData);
		if (FAILED(m_hResult))
		{
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, (WPARAM)m_hResult, (LPARAM)_T("FAILED iDiscFormatRaw->WriteMedia"));
		}
	}

	delete eventSink;

	if (SUCCEEDED(m_hResult))
	{
		return true;
	}

	m_errorMessage.Format(_T("IDiscFormat2RawCD->Write Failed! Error:0x%08x"), m_hResult);

	return true;

}

IDiscFormat2RawCD* CDiscFormatRawCD::GetIDiscFormatRawCDPtr()
{
	return m_discFormatRawCD;
}
